//! `std::net` 模块的测试用例
//!
//! 本文件包含对 `std::net` 中网络相关功能的测试，
//! 包括 `IpAddr`, `SocketAddr`, `TcpListener`, `TcpStream`, 和 `UdpSocket`。
//! 注意：这些测试会尝试绑定到本地网络端口，可能会因为端口占用而失败。

#[cfg(test)]
mod tests {
    use std::io::{Read, Write};
    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener, TcpStream, UdpSocket};
    use std::thread;

    // --- IP 地址和套接字地址测试 ---

    /// 测试 IP 地址的创建和属性
    #[test]
    fn test_ip_addr() {
        let ipv4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
        let ipv6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));

        assert!(ipv4.is_loopback());
        assert!(ipv6.is_loopback());
        assert!(!ipv4.is_multicast());
    }

    /// 测试套接字地址的解析
    #[test]
    fn test_socket_addr_parsing() {
        let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
        assert_eq!(addr.ip(), Ipv4Addr::new(127, 0, 0, 1));
        assert_eq!(addr.port(), 8080);

        let addr_v6: SocketAddr = "[::1]:8080".parse().unwrap();
        assert_eq!(addr_v6.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
    }

    // --- TCP 测试 ---

    /// 测试 TCP 监听和连接
    #[test]
    fn test_tcp_listener_and_stream() {
        // 绑定到一个未使用的端口
        let listener = TcpListener::bind("127.0.0.1:0").unwrap();
        let local_addr = listener.local_addr().unwrap();

        // 在一个新线程中模拟客户端连接
        let client_thread = thread::spawn(move || {
            let mut stream = TcpStream::connect(local_addr).unwrap();
            stream.write_all(b"hello").unwrap();
        });

        // 接受客户端连接
        let (mut stream, _addr) = listener.accept().unwrap();
        let mut buffer = [0; 5];
        stream.read_exact(&mut buffer).unwrap();

        assert_eq!(&buffer, b"hello");

        client_thread.join().unwrap();
    }

    // --- UDP 测试 ---

    /// 测试 UDP 套接字的发送和接收
    #[test]
    fn test_udp_socket() {
        // 绑定两个 UDP 套接字
        let socket1 = UdpSocket::bind("127.0.0.1:0").unwrap();
        let addr1 = socket1.local_addr().unwrap();

        let socket2 = UdpSocket::bind("127.0.0.1:0").unwrap();
        let addr2 = socket2.local_addr().unwrap();

        // 从 socket1 发送数据到 socket2
        socket1.send_to(b"ping", addr2).unwrap();

        // 从 socket2 接收数据
        let mut buffer = [0; 4];
        let (number_of_bytes, src_addr) = socket2.recv_from(&mut buffer).unwrap();

        assert_eq!(number_of_bytes, 4);
        assert_eq!(&buffer, b"ping");
        assert_eq!(src_addr, addr1);
    }

    /// 测试 UDP `connect` 方法
    /// `connect` 后，可以使用 `send` 和 `recv`，而不需要每次都指定地址
    #[test]
    fn test_udp_connected() {
        let socket1 = UdpSocket::bind("127.0.0.1:0").unwrap();
        let addr1 = socket1.local_addr().unwrap();

        let socket2 = UdpSocket::bind("127.0.0.1:0").unwrap();
        let addr2 = socket2.local_addr().unwrap();

        // 将两个套接字“连接”到对方
        socket1.connect(addr2).unwrap();
        socket2.connect(addr1).unwrap();

        // 发送数据
        socket1.send(b"connected").unwrap();

        // 接收数据
        let mut buffer = [0; 9];
        socket2.recv(&mut buffer).unwrap();

        assert_eq!(&buffer, b"connected");
    }
}
